#include "stdafx.h"
#include "PdfFileAccess.h"

std::unique_ptr<char, pdfium::FreeDeleter> GetFileContents(const char* filename,
	size_t* retlen) {
	FILE* file = fopen(filename, "rb");
	if (!file) {
		fprintf(stderr, "Failed to open: %s\n", filename);
		return nullptr;
	}
	(void)fseek(file, 0, SEEK_END);
	size_t file_length = ftell(file);
	if (!file_length) {
		return nullptr;
	}
	(void)fseek(file, 0, SEEK_SET);
	std::unique_ptr<char, pdfium::FreeDeleter> buffer(
		static_cast<char*>(malloc(file_length)));
	if (!buffer) {
		return nullptr;
	}
	size_t bytes_read = fread(buffer.get(), 1, file_length, file);
	(void)fclose(file);
	if (bytes_read != file_length) {
		fprintf(stderr, "Failed to read: %s\n", filename);
		return nullptr;
	}
	*retlen = bytes_read;
	return buffer;
}

PdfFileAccess::PdfFileAccess()
{
	this->m_FileLen = 0;
	this->m_Param = this;
	this->m_GetBlock = &__GetBlock;
}

PdfFileAccess::~PdfFileAccess()
{
}

int PdfFileAccess::__GetBlock(void* param, unsigned long position, unsigned char* pBuf, unsigned long size)
{
	return reinterpret_cast<PdfFileAccess*>(param)->GetBlock(position, pBuf, size);
}


PdfFileAccessImpl::PdfFileAccessImpl(LPCWSTR lpszPath)
{
	file_contents_ = GetFileContents(w2a(lpszPath).c_str(), &file_length_);
	if (!file_contents_)
		return;
	m_FileLen = static_cast<unsigned long>(file_length_);
}

PdfFileAccessImpl::~PdfFileAccessImpl()
{

}

int PdfFileAccessImpl::GetBlock(unsigned long position, unsigned char* pBuf, unsigned long size)
{
	if (position + size < position || position + size > m_FileLen) {
		printf("GetBlock not reached.\n");
		return 0;
	}

	if (file_contents_ == nullptr) {
		printf("GetBlock filedata error.\n");
		return 0;
	}

	memcpy(pBuf, file_contents_.get() + position, size);
	printf("GetBlock=%lu\n", position);
	return size;
}

//////////////////////////////////////////////////////////////////////////
PdfFileWrite::PdfFileWrite(LPCWSTR lpszPath)
{
	FPDF_FILEWRITE::version = 1;
	FPDF_FILEWRITE::WriteBlock = WriteBlockCallback;
	filestream_.open(lpszPath, std::ios::binary);
}

PdfFileWrite::~PdfFileWrite()
{
	if (filestream_.is_open())
		filestream_.close();
}

// static
int PdfFileWrite::WriteBlockCallback(FPDF_FILEWRITE* pFileWrite, const void* data, unsigned long size) {
	PdfFileWrite* pThis = static_cast<PdfFileWrite*>(pFileWrite);

	pThis->data_string_.append(static_cast<const char*>(data), size);

	if (pThis->filestream_.is_open())
		pThis->filestream_.write(static_cast<const char*>(data), size);
	else {
		printf("WriteBlock failed because the file is not opened.\n");
		return 0;
	}

	printf("WriteBlock %lu byte.\n", size);
	return 1;
}

//////////////////////////////////////////////////////////////////////////
PdfFileAvail::PdfFileAvail()
{
	this->version = 1;
	this->IsDataAvail = &__IsDataAvail;
}

FPDF_BOOL PdfFileAvail::__IsDataAvail(struct _FX_FILEAVAIL* pThis, size_t offset, size_t size)
{
	return reinterpret_cast<PdfFileAvail*>(pThis)->_IsDataAvail(offset, size);
}

//////////////////////////////////////////////////////////////////////////
PdfDownloadHints::PdfDownloadHints()
{
	this->version = 1;
	this->AddSegment = &__AddSegment;
}

void PdfDownloadHints::__AddSegment(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size)
{
	return reinterpret_cast<PdfDownloadHints*>(pThis)->_AddSegment(offset, size);
}
